library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity link_controller is

  port ( clk          : in  std_ulogic;
         host_address : in  std_logic_vector(31 DownTo 0);
         data_in_n    : in  std_ulogic;
         data_in_ne   : in  std_ulogic;
         data_in_nw   : in  std_ulogic;
         data_in_s    : in  std_ulogic;
         data_in_se   : in  std_ulogic;
         data_in_sw   : in  std_ulogic;
         data_in_e    : in  std_ulogic;
         data_in_w    : in  std_ulogic;
         data_out_n   : out std_ulogic;
         data_out_ne  : out std_ulogic;
         data_out_nw  : out std_ulogic;
         data_out_s   : out std_ulogic;
         data_out_se  : out std_ulogic;
         data_out_sw  : out std_ulogic;
         data_out_e   : out std_ulogic;
         data_out_w   : out std_ulogic
       );

end link_controller; 

architecture bhv of link_controller is
  
  component link is

    port ( clk            : in  std_ulogic;
           initialize     : in  std_ulogic;
           reset_in       : in  std_ulogic;
           link_data_in   : in  std_ulogic;
           h_target_label : in  std_logic_vector(31 DownTo 0);
           reset_out      : out std_ulogic;
           link_data_out  : out std_ulogic;
           link_killed    : out std_ulogic
         );
    
  end component;

  -- type defs
  type controller_state_t is (state0, state1, state2, state3, state4, state5, state6, state7, state8, state9);

  -- Global Signals

  -- controller specific signals
  signal controller_host_address     : std_logic_vector(31 DownTo 0);

  -- link a specific signals
  signal init_n                      : std_ulogic;
  signal reset_n                     : std_ulogic;
  signal reset_out_n                 : std_ulogic;
  signal target_label_n              : std_logic_vector(31 DownTo 0);
  signal link_killed_n               : std_ulogic;

  signal init_ne                     : std_ulogic;
  signal reset_ne                    : std_ulogic;
  signal reset_out_ne                : std_ulogic;
  signal target_label_ne             : std_logic_vector(31 DownTo 0);
  signal link_killed_ne              : std_ulogic;

  signal init_nw                     : std_ulogic;
  signal reset_nw                    : std_ulogic;
  signal reset_out_nw                : std_ulogic;
  signal target_label_nw             : std_logic_vector(31 DownTo 0);
  signal link_killed_nw              : std_ulogic;

  signal init_s                      : std_ulogic;
  signal reset_s                     : std_ulogic;
  signal reset_out_s                 : std_ulogic;
  signal target_label_s              : std_logic_vector(31 DownTo 0);
  signal link_killed_s               : std_ulogic;

  signal init_se                     : std_ulogic;
  signal reset_se                    : std_ulogic;
  signal reset_out_se                : std_ulogic;
  signal target_label_se             : std_logic_vector(31 DownTo 0);
  signal link_killed_se              : std_ulogic;

  signal init_sw                     : std_ulogic;
  signal reset_sw                    : std_ulogic;
  signal reset_out_sw                : std_ulogic;
  signal target_label_sw             : std_logic_vector(31 DownTo 0);
  signal link_killed_sw              : std_ulogic;

  signal init_e                      : std_ulogic;
  signal reset_e                     : std_ulogic;
  signal reset_out_e                 : std_ulogic;
  signal target_label_e              : std_logic_vector(31 DownTo 0);
  signal link_killed_e               : std_ulogic;

  signal init_w                      : std_ulogic;
  signal reset_w                     : std_ulogic;
  signal reset_out_w                 : std_ulogic;
  signal target_label_w              : std_logic_vector(31 DownTo 0);
  signal link_killed_w               : std_ulogic;

  signal link_clk                    : std_ulogic;

begin

  link_n  : link port map ( link_clk, 
                            init_n, 
                            reset_n,
                            data_in_n,
                            target_label_n,
                            reset_out_n,
                            data_out_n,
                            link_killed_n
                          );

  link_ne : link port map ( link_clk, 
                            init_ne, 
                            reset_ne,
                            data_in_ne,
                            target_label_ne,
                            reset_out_ne,
                            data_out_ne,
                            link_killed_ne
                          );

  link_nw : link port map ( link_clk, 
                            init_nw, 
                            reset_nw,
                            data_in_nw,
                            target_label_nw,
                            reset_out_nw,
                            data_out_nw,
                            link_killed_nw
                          );

  link_s  : link port map ( link_clk, 
                            init_s, 
                            reset_s,
                            data_in_s,
                            target_label_s,
                            reset_out_s,
                            data_out_s,
                            link_killed_s
                          );

  link_se : link port map ( link_clk, 
                            init_se, 
                            reset_se,
                            data_in_se,
                            target_label_se,
                            reset_out_se,
                            data_out_se,
                            link_killed_se
                          );

  link_sw : link port map ( link_clk, 
                            init_sw, 
                            reset_sw,
                            data_in_sw,
                            target_label_sw,
                            reset_out_sw,
                            data_out_sw,
                            link_killed_sw
                          );

  link_e  : link port map ( link_clk, 
                            init_e, 
                            reset_e,
                            data_in_e,
                            target_label_e,
                            reset_out_e,
                            data_out_e,
                            link_killed_e
                          );

  link_w  : link port map ( link_clk, 
                            init_w, 
                            reset_w,
                            data_in_w,
                            target_label_w,
                            reset_out_w,
                            data_out_w,
                            link_killed_w
                          );

  link_controller_control: process ( clk )

    variable controller_state : controller_state_t := state0;

    procedure clock_links is
    begin
      link_clk <= '1';
      link_clk <= '0';
    end procedure clock_links;

  begin

    if( clk'event and clk = '1' ) then
      case controller_state is 
        when state0 =>
          clock_links;
          controller_state := state1;
        when state1 =>
          clock_links;
          controller_state := state2;
        when state2 =>
          clock_links;
          controller_state := state3;
        when state3 =>
          clock_links;
          controller_state := state4;
        when state4 =>
          clock_links;
          controller_state := state5;
        when state5 =>
          clock_links;
          controller_state := state6;
        when state6 =>
          clock_links;
          controller_state := state7;
        when state7 =>
          controller_state := state8;
        when state8 =>
          controller_state := state9;
        when state9 =>
          controller_state := state0;
      end case;
    end if;

  end process link_controller_control;

  link_controller_set_host_address : process ( host_address )
  begin

    if ( host_address'event ) then
      controller_host_address <= host_address;
    end if;

  end process link_controller_set_host_address;

end bhv;

